from rest_framework import serializers
from .models import User, Memorandum, UserDetail, Address, Application
from school.models import School, Role
from rest_framework.exceptions import AuthenticationFailed
from backend.serializers import RoleSerializer
from rest_framework.exceptions import ValidationError, APIException
import re
from django.core.cache import cache
from django.conf import settings
from libs.common_jwt import JwtToken


class UserRegisterSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True, required=False)
    school = serializers.PrimaryKeyRelatedField(queryset=School.objects.all())

    class Meta:
        model = User
        fields = '__all__'
        extra_kwargs = {
            'position': {'required': False},
            'role': {'required': False}
        }

    def create(self, validated_data):
        validated_data['nick_name'] = 'nick_' + validated_data.get('username')
        password = validated_data.pop('password', '123456')
        new_pwd = User.make_password(password)
        position = validated_data.pop('position', None)
        role = validated_data.pop('role', [])
        user = User.objects.create(**validated_data, password=new_pwd)
        user.position = position
        user.role.set(role)
        user.save()
        return user


class SchoolSerializer(serializers.ModelSerializer):
    class Meta:
        model = School
        fields = '__all__'


class UserInfoSerializer(UserRegisterSerializer):
    password = serializers.CharField(write_only=True, required=False)
    roles = RoleSerializer(source='role', many=True, required=False, read_only=True)
    role = serializers.PrimaryKeyRelatedField(queryset=Role.objects.all(), many=True, required=False)
    school = serializers.PrimaryKeyRelatedField(queryset=School.objects.all(), required=False)

    # school = SchoolSerializer(source='school', read_only=True)

    class Meta:
        model = User
        fields = '__all__'
        extra_kwargs = {
            'username': {'required': False},
            'position': {'required': False},
        }
        depth = 1

    def validate_password(self, password):
        is_old = self.instance.check_password(password)
        if is_old:
            raise ValidationError('新密码不能与旧密码相同')
        else:
            return self.instance.make_password(password)

    def update(self, instance, validated_data):
        role = validated_data.pop('role', [])
        instance.role.set(role)
        for key, value in validated_data.items():
            setattr(instance, key, value)
        instance.save()
        if validated_data.get('password'):
            raise AuthenticationFailed('请重新登录')
        return instance


class UserLoginSerializer(serializers.ModelSerializer):
    username = serializers.CharField()
    password = serializers.CharField(allow_null=True, required=False, write_only=True)
    captcha = serializers.CharField(allow_null=True, required=False, write_only=True)

    class Meta:
        model = User
        fields = '__all__'

    def _make_token(self, user):
        token = JwtToken.get_token(user)
        cache.set(f'token_{user.pk}', token, timeout=60 * 60 * 24 * 7)
        # 将登录用户放在request中
        self.context.get('request').user = user
        # 将token放在context中
        self.context['token'] = token
        self.instance = user

    def _mul_login(self, username, password):
        # 多方式登录
        if re.match(r'^1[3-9][0-9]{9}$', username):
            # 手机号
            user = User.objects.filter(phone=username).first()
        elif re.match('^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$', username):
            # 邮箱
            user = User.objects.filter(email=username).first()
        else:
            # 用户名
            user = User.objects.filter(username=username).first()

        if user and user.check_password(password):
            # 生成token+将user放在request中
            self._make_token(user)
            return user
        else:
            raise ValidationError({'username': '用户名或密码错误'})

    def _sms_login(self, mobile, captcha):
        user = User.objects.filter(phone=mobile).first()
        assert user, ValueError('该手机号用户没注册')
        # 校验验证码
        old_code = cache.get(f'sms_captcha_{mobile}')
        # 非生产环境可以使用万能验证码
        assert old_code == captcha or (settings.DEBUG and captcha == '8888'), ValueError('验证码错误')
        # 生成token+将user放在request中
        self._make_token(user)
        return user

    def validate(self, attrs):
        username = attrs.get('username')
        password = attrs.get('password')
        captcha = attrs.get('captcha')
        # 密码或使用code登录，两者必须带一种
        if password:
            # 如果带了密码，就意味着是用户名+密码登录
            user = self._mul_login(username, password)
        elif captcha:
            # 如果带了验证码，就意味着是电话+短信验证码登录
            user = self._sms_login(mobile=username, captcha=captcha)
        else:
            raise APIException('参数缺失，请补足参数')
        return attrs


class UserWxLoginSerializer(UserLoginSerializer):
    '''
    继承UserLoginSerializer，重写_sms_login
    '''

    def _create_user(self, mobile, school):
        '''
        微信小程序登录时，如果没有注册过，注册+登录
        手机号作为用户名和昵称
        '''
        # 默认密码：123456
        password = User.make_password('123456')
        user = User.objects.create(username=mobile, nick_name=f'wx_{mobile}', phone=mobile, password=password,
                                   school_id=school)
        return user

    def _sms_login(self, mobile, captcha):
        # 校验验证码
        old_code = cache.get(f'sms_captcha_{mobile}')
        # 非生产环境可以使用万能验证码
        assert old_code == captcha or (settings.DEBUG and captcha == '8888'), ValueError('验证码错误')
        user = User.objects.filter(phone=mobile).first()
        if not user:
            school = self.context.get('school')
            user = self._create_user(mobile=mobile, school=school)
        # 生成token+将user放在request中
        self._make_token(user)
        return user


class MemrSerializer(serializers.ModelSerializer):
    class Meta:
        model = Memorandum
        fields = '__all__'


class UserIDInfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserDetail
        fields = '__all__'


class UserAddressSerializer(serializers.ModelSerializer):
    class Meta:
        model = Address
        fields = '__all__'


class ApplicationSerializer(serializers.ModelSerializer):
    applicant_id = serializers.PrimaryKeyRelatedField(source='applicant', queryset=User.objects.all(), required=False)
    school_id = serializers.PrimaryKeyRelatedField(queryset=School.objects.all(), source='school', write_only=True,
                                                   required=False)

    class Meta:
        model = Application
        fields = ['id', 'category', 'get_category', 'state', 'get_state', 'applicant', 'applicant_id', 'reviewer',
                  'content', 'school_id', 'create_time']
        depth = 1

    def _order_taker(self, instance, state, request):
        # 小程序端校验时，校验角色列表中是否含有接单员
        order_taker = Role.objects.filter(name='接单员').first()
        instance.reviewer = request.user
        user = instance.applicant
        if state == 1:
            # 如果接单员申请审核通过，将接单员的角色添加到指定用户的权限中
            user.role.add(order_taker)
            # print(user.memorandum_set.all())
            Memorandum.objects.create(user=user, title='接单员审核通过', content='恭喜你成为接单员')
        else:
            Memorandum.objects.create(user=user, title='接单员审核驳回', content='请重新提交资料申请')
        instance.state = state
        instance.save()

    def update(self, instance, validated_data):
        request = self.context.get('request')
        # 如果是修改任务状态，根据分类执行不同的方法
        state = validated_data.get('state')
        if state:
            if instance.category == 0:
                # 接单员申请
                self._order_taker(instance, state, request)
            return instance
        else:
            # 如果是修改申请内容，正常修改即可
            return super().update(instance, validated_data)
